package repository

import (
	"awesomeProject/internal/model"
	"awesomeProject/pkg/errors"
	"context"

	"gorm.io/gorm"
)

type PostRepository interface {
	// CRUD
	Create(ctx context.Context, post *model.Post) error        // 创建帖子
	GetByID(ctx context.Context, id uint) (*model.Post, error) // 根据id拿到帖子
	Update(ctx context.Context, post *model.Post) error        // 更新帖子
	Delete(ctx context.Context, id uint) error                 // 删除帖子

	// 查询
	List(ctx context.Context, page, pageSize int) ([]*model.Post, int64, error)                            // 分页查询帖子
	ListByCategory(ctx context.Context, categoryID uint, page, pageSize int) ([]*model.Post, int64, error) // 根据分类查询帖子
	ListByUser(ctx context.Context, userID uint, page, pageSize int) ([]*model.Post, int64, error)         // 根据用户id查询帖子
	ListUserFavorites(ctx context.Context, userID uint, page, pageSize int) ([]*model.Post, int64, error)  // 根据用户id查询收藏的帖子

	// 点赞和收藏
	AddLike(ctx context.Context, postID, userID uint) error           // 点赞
	RemoveLike(ctx context.Context, postID, userID uint) error        // 取消点赞
	AddFavourite(ctx context.Context, postID, userID uint) error      // 收藏
	RemoveFavourite(ctx context.Context, postID, userID uint) error   // 取消收藏
	GetLikeCount(ctx context.Context, postID uint) (int64, error)     // 获取点赞数量
	GetFavoriteCount(ctx context.Context, postID uint) (int64, error) // 获取收藏数量
}

// postRepository 帖子仓库接口实现
type postRepository struct {
	db *gorm.DB
}

// NewPostRepository 创建帖子仓库实例
func NewPostRepository(db *gorm.DB) PostRepository {
	return &postRepository{db: db}
}

// Create 创建帖子
func (r *postRepository) Create(ctx context.Context, post *model.Post) error {
	// 使用事务确保数据的一致性
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 创建帖子的记录
		result := tx.Create(post)
		return result.Error
	})
}

// GetByID 根据id查询帖子
func (r *postRepository) GetByID(ctx context.Context, id uint) (*model.Post, error) {
	var post model.Post
	// 预加载关联数据
	result := r.db.WithContext(ctx).Preload("User").Preload("Category").Preload("Comments").First(&post, id)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			return nil, errors.ErrPostNotFound
		}
		return nil, errors.ErrInternalError
	}
	return &post, nil
}

// Update 更新帖子
func (r *postRepository) Update(ctx context.Context, post *model.Post) error {
	result := r.db.WithContext(ctx).Save(post)
	if result.Error != nil {
		return errors.ErrInternalError
	}
	return nil
}

// Delete 删除帖子
func (r *postRepository) Delete(ctx context.Context, id uint) error {
	// 还是使用事务保证数据一致性
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 删除帖子记录 这里是软删除因为使用了gorm.Model
		result := tx.Delete(&model.Post{}, id)
		if result.Error != nil {
			return errors.ErrInternalError
		}
		if result.RowsAffected == 0 {
			return errors.ErrPostNotFound
		}
		return nil
	})
}

// List 分页查询帖子 获取帖子列表
func (r *postRepository) List(ctx context.Context, page, pageSize int) ([]*model.Post, int64, error) {
	var posts []*model.Post
	var counts int64
	// 算出帖子的数量
	if err := r.db.WithContext(ctx).Model(&model.Post{}).Count(&counts).Error; err != nil {
		return nil, 0, errors.ErrInternalError
	}
	// 进行分页查询
	offset := (page - 1) * pageSize
	result := r.db.WithContext(ctx).Preload("User").Preload("Category").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&posts)
	if result.Error != nil {
		return nil, 0, errors.ErrInternalError
	}
	return posts, counts, nil
}

// ListByCategory 根据分类查询帖子
func (r *postRepository) ListByCategory(ctx context.Context, categoryID uint, page, pageSize int) ([]*model.Post, int64, error) {
	var posts []*model.Post
	var counts int64

	// 算出帖子数量
	if err := r.db.WithContext(ctx).Model(&model.Post{}).Where("category_id = ?", categoryID).Count(&counts).Error; err != nil {
		return nil, 0, errors.ErrInternalError
	}
	// 进行分页查询
	offset := (page - 1) * pageSize
	result := r.db.WithContext(ctx).Where("category_id = ?", categoryID).Preload("User").Preload("Category").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&posts)
	if result.Error != nil {
		return nil, 0, errors.ErrInternalError
	}
	return posts, counts, nil
}

// ListByUser 根据用户id查询帖子
func (r *postRepository) ListByUser(ctx context.Context, userID uint, page, pageSize int) ([]*model.Post, int64, error) {
	var posts []*model.Post
	var counts int64

	// 算出帖子数量
	if err := r.db.WithContext(ctx).Model(&model.Post{}).Where("user_id = ?", userID).Count(&counts).Error; err != nil {
		return nil, 0, errors.ErrInternalError
	}
	// 进行分页查询
	offset := (page - 1) * pageSize
	result := r.db.WithContext(ctx).Where("user_id = ?", userID).Preload("User").Preload("Category").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&posts)
	if result.Error != nil {
		return nil, 0, errors.ErrInternalError
	}
	return posts, counts, nil
}

// AddLike 点赞
func (r *postRepository) AddLike(ctx context.Context, postID, userID uint) error {
	// 事务保证数据一致性
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 先查询帖子存不存在
		var post model.Post
		if err := tx.First(&post, postID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				return errors.ErrPostNotFound
			}
			return errors.ErrInternalError
		}
		// 再查询用户是否存在
		var user model.User
		if err := tx.First(&user, userID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				return errors.ErrUserNotFound
			}
			return errors.ErrInternalError
		}
		// 添加点赞的关系
		if err := tx.Exec("INSERT INTO user_post_likes (user_id,post_id) VALUES (?,?)", userID, postID).Error; err != nil {
			return errors.ErrInternalError
		}
		return nil
	})
}

// RemoveLike 取消点赞
func (r *postRepository) RemoveLike(ctx context.Context, postID, userID uint) error {
	result := r.db.WithContext(ctx).Exec("DELETE FROM user_post_likes WHERE user_id = ? AND post_id = ?", userID, postID)
	if result.Error != nil {
		return errors.ErrInternalError
	}
	if result.RowsAffected == 0 {
		return errors.ErrPostLikeNotExists
	}
	return nil
}

// AddFavourite 收藏
func (r *postRepository) AddFavourite(ctx context.Context, postID, userID uint) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 查询帖子是否存在
		var post model.Post
		if err := tx.First(&post, postID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				return errors.ErrPostNotFound
			}
			return errors.ErrInternalError
		}
		// 查询用户是否存在
		var user model.User
		if err := tx.First(&user, userID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				return errors.ErrUserNotFound
			}
			return errors.ErrInternalError
		}
		// 添加收藏的关系
		if err := tx.Exec("INSERT INTO user_post_favorites (user_id,post_id) VALUES (?,?)", userID, postID).Error; err != nil {
			return errors.ErrInternalError
		}
		return nil
	})
}

// RemoveFavourite 取消收藏
func (r *postRepository) RemoveFavourite(ctx context.Context, postID, userID uint) error {
	result := r.db.WithContext(ctx).Exec("DELETE FROM user_post_favorites WHERE user_id = ? AND post_id = ?", userID, postID)
	if result.Error != nil {
		return errors.ErrInternalError
	}
	if result.RowsAffected == 0 {
		return errors.ErrPostFavNotExists
	}
	return nil
}

// GetLikeCount 获取点赞数量
func (r *postRepository) GetLikeCount(ctx context.Context, postID uint) (int64, error) {
	var count int64
	err := r.db.WithContext(ctx).Model(&model.User{}).Where("id IN (SELECT user_id FROM user_post_likes WHERE post_id = ?)", postID).Count(&count).Error
	if err != nil {
		return 0, errors.ErrInternalError
	}
	return count, nil
}

// GetFavoriteCount 获取收藏数量
func (r *postRepository) GetFavoriteCount(ctx context.Context, postID uint) (int64, error) {
	var count int64
	err := r.db.WithContext(ctx).Model(&model.User{}).Where("id IN (SELECT user_id FROM user_post_favorites WHERE post_id = ?)", postID).Count(&count).Error
	if err != nil {
		return 0, errors.ErrInternalError
	}
	return count, nil
}

// ListUserFavorites 根据用户id查询收藏的帖子
func (r *postRepository) ListUserFavorites(ctx context.Context, userID uint, page, pageSize int) ([]*model.Post, int64, error) {
	var posts []*model.Post
	var total int64

	// 计算偏移量
	offset := (page - 1) * pageSize

	// 查询用户收藏的帖子总数
	err := r.db.WithContext(ctx).Model(&model.Post{}).
		Joins("JOIN user_post_favorites ON posts.id = user_post_favorites.post_id").
		Where("user_post_favorites.user_id = ?", userID).
		Count(&total).Error
	if err != nil {
		return nil, 0, errors.ErrInternalError
	}

	// 查询用户收藏的帖子列表
	err = r.db.WithContext(ctx).
		Joins("JOIN user_post_favorites ON posts.id = user_post_favorites.post_id").
		Where("user_post_favorites.user_id = ?", userID).
		Preload("User").
		Preload("Category").
		Order("user_post_favorites.created_at DESC").
		Offset(offset).
		Limit(pageSize).
		Find(&posts).Error
	if err != nil {
		return nil, 0, errors.ErrInternalError
	}

	return posts, total, nil
}
